﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace DrawingObjects
{
    class DrawingObject : Panel
    {
        public String ElementType { get; private set; }
        private Point _pointCreate;
        private Point _pointMove;
        private bool _waitMouseUp;
        private Bitmap _bitmap;
        private Pen _pen;

        public DrawingObject(MouseEventArgs e, String element, Color color, int penSize)
        {
            _waitMouseUp = true;
            Left = _pointCreate.X = e.X;
            Top = _pointCreate.Y = e.Y;
            ElementType = element;
            _pen = new Pen(color) { Width = penSize };
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            BackColor = Color.Transparent;
            SetStyle(ControlStyles.Opaque, true);
        }

        public DrawingObject(String element, int x, int y, int w, int h, int color, int penSize)
        {
            _waitMouseUp = false;
            Left = _pointCreate.X = x;
            Top = _pointCreate.Y = y;
            Width = w;
            Height = h;
            ElementType = element;
            _pen = new Pen(Color.FromArgb(color)) { Width = penSize };
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            BackColor = Color.Transparent;
            SetStyle(ControlStyles.Opaque, true);
            DrawObject();
        }

        private void DrawObject()
        {
            if (Width > 0 && Height > 0)
                _bitmap = new Bitmap(Width, Height);
            else return;
            var graphics = Graphics.FromImage(_bitmap);
            switch (ElementType)
            {
                case "Line":
                    var pt1 = new Point();
                    var pt2 = new Point();
                    if (_pointCreate.X > Left) 
                    { 
                        pt1.X = 0; 
                        pt2.X = Width; 
                    }
                    else 
                    { 
                        pt1.X = Width; 
                        pt2.X = 0; 
                    }
                    if (_pointCreate.Y > Top) 
                    { 
                        pt1.Y = 0; 
                        pt2.Y = Height; 
                    }
                    else 
                    { 
                        pt1.Y = Height; 
                        pt2.Y = 0; 
                    }
                    graphics.DrawLine(_pen, pt1.X, pt1.Y, pt2.X, pt2.Y);
                    break;
                case "Ellipse":
                    graphics.DrawEllipse(_pen, 1, 1, Math.Abs(Right - Left) - 2, Math.Abs(Bottom - Top) - 2);
                    break;
                case "Rectangle":
                    graphics.DrawRectangle(_pen, 0, 0, Math.Abs(Right - Left) - 1, Math.Abs(Bottom - Top) - 1);
                    break;
                case "Circle":
                    graphics.DrawEllipse(_pen, 0, 0, Bottom / 4, Bottom / 4);
                    break;
            }
            graphics.Dispose();
        }

        public override string ToString()
        {
            return "<ELEMENT>\n" +
                "<TYPE>" + ElementType + "</TYPE>\n" +
                "<XPosition>" + Left + "</XPosition>\n" +
                "<YPosition>" + Top + "</YPosition>\n" +
                "<Width>" + Width + "</Width>\n" +
                "<Height>" + Height + "</Height>\n" + 
                "<Color>" + _pen.Color.ToArgb() + "</Color>\n" +
                "<PenSize>" + _pen.Width + "</PenSize>\n" + 
                "</ELEMENT>";
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (_bitmap == null) return;
            var graphics = e.Graphics;
            graphics.DrawImage(_bitmap, 0, 0);
            graphics.Dispose();
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);
            if (Parent != null)
                if (_waitMouseUp)
                {
                    BorderStyle = BorderStyle.FixedSingle;
                    Parent.MouseUp += ParentOnMouseUp;
                    Parent.MouseMove += ParentOnMouseMove;
                }
            else Dispose();
        }

        private void ParentOnMouseMove(object sender, MouseEventArgs e)
        {
            base.OnMouseMove(e);
            var xDif = e.X - _pointCreate.X;
            var yDif = e.Y - _pointCreate.Y;
            if (xDif < 0) 
                Left = e.X;
            if (yDif < 0) 
                Top = e.Y;
            Width = Math.Abs(xDif);
            Height = Math.Abs(yDif);
            Invalidate();
        }

        private void ParentOnMouseUp(object sender, MouseEventArgs e)
        {
            base.OnMouseUp(e);
            DrawObject();
            BorderStyle = BorderStyle.None;
            Parent.MouseUp -= ParentOnMouseUp;
            Parent.MouseMove -= ParentOnMouseMove;
            _pointMove = new Point();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            _pointMove.X = e.X;
            _pointMove.Y = e.Y;
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (e.Button != MouseButtons.Left) return;
            Left += e.X - _pointMove.X;
            Top += e.Y - _pointMove.Y;
            Parent.Invalidate();
        }

        protected override CreateParams CreateParams
        {
            get
            {
                const int transparent = 0x00000020;
                var createParams = base.CreateParams;
                createParams.ExStyle |= transparent;
                return createParams;
            }
        }
    }
}
